﻿/*
 * Copyright (C) 2012, Jesus Requejo <jesus.requejo@gmail.com> 
 * Licensed under Microsoft Public License (Ms-PL)
 * http://www.microsoft.com/en-us/openness/licenses.aspx#MPL
*/

namespace Infrastructure {

   using System;
   using System.Collections;
   using System.Collections.Generic;
   using System.DirectoryServices;
   using System.Linq;
   using System.Security.Principal;

   public class WindowsUser {
      public string Name { get; set; }
      public string Schema { get; set; }

      public WindowsUser(string name, string schema) {
         Name = name;
         Schema = schema;
      }
   }

   public static class WindowsUsersUtils {

      public static string GetCurrentUserName() {
         WindowsIdentity id = WindowsIdentity.GetCurrent();
         return ConvertHostNameToUpperCase(id.Name);
      }

      public static bool UserHasAdministratorPriviledges() {
         WindowsIdentity id = WindowsIdentity.GetCurrent();
         WindowsPrincipal p = new WindowsPrincipal(id);
         bool inRole = p.IsInRole(WindowsBuiltInRole.Administrator);
         return inRole;
      }

      public static IEnumerable<WindowsUser> GetAllInteractiveUsers() {
         DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
         DirectoryEntry admGroup = localMachine.Children.Find("users", "group");
         IEnumerable members = (IEnumerable)admGroup.Invoke("members", null);

         var users = members.Cast<object>().
            Select(x => new DirectoryEntry(x)).
            Where(dirEntry => dirEntry.SchemaClassName == "User").
            Select(dirEntry =>
               new WindowsUser(
                  Environment.MachineName + @"\" + dirEntry.Name,
                  dirEntry.SchemaClassName
               )
            );

         return users;
      }

      public static IEnumerable<WindowsUser> GetAllAdminUsers() {
         DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
         DirectoryEntry admGroup = localMachine.Children.Find("Administrators", "group");
         IEnumerable members = (IEnumerable)admGroup.Invoke("members", null);

         var users = members.Cast<object>().
            Select(x => new DirectoryEntry(x)).
            Where(dirEntry => dirEntry.SchemaClassName == "User").
            Select(dirEntry =>
               new WindowsUser(
                  Environment.MachineName + @"\" + dirEntry.Name,
                  dirEntry.SchemaClassName
               )
            );

         return users;
      }

      public static bool CurrentUserIsInAdminGroup() {
         WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
         return UserIsInAdminGroup(currentUser);                  
      }

      public static bool UserIsInAdminGroup(WindowsIdentity user) {
         IdentityReferenceCollection userGroups = user.Groups;
         var isAdmin = userGroups.Cast<IdentityReference>().
            Select(group => group.Translate(typeof(NTAccount))).
               Where(gr => gr.Value == @"BUILTIN\Administrators").DefaultIfEmpty();

         return isAdmin != null;
      }

      /// <summary>
      /// Returns true if the supplied user belongs to the administrators group
      /// </summary>
      /// <param name="userName">User name in format DOMAIN\Username</param>
      /// <returns></returns>
      public static bool UserIsInAdminGroup(string name) {
         var userName = ConvertHostNameToUpperCase(name);
         var allAdmins = GetAllAdminUsers();
         return allAdmins.Select(admin => admin.Name).Contains(userName);
      }

      public static string ConvertHostNameToUpperCase(string userName) {
         var parts = userName.Split('\\');
         return parts[0].ToUpperInvariant() + @"\" + parts[1];
      }
   }
}
